#include "CentralCache.h"
#include "PageCache.h"


Span* CentralCache::GetOneSpan(SpanList& list, size_t size) {
    Span* it = list.Begin();
    while (it != list.End()) {
        if (it->_freeList != nullptr) {
            
            return it;
        }
        it = it->_next;
    }
    //申请newspan时先解锁
    list.mtx.unlock();

	//newspan对PageCache加锁
    PageCache::GetInstance()->mtx.lock();
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    span->_isUsed = true;
    span->_size = size;
    PageCache::GetInstance()->mtx.unlock();
    

	//将span进行切分
    char* start = reinterpret_cast<char*> ((span->_pageId) << PAGE_SHIFT);
    size_t bytes =  span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;
    size_t i = 1;
    while (start < end)
    {
        ++i;
        NextObj(tail) = start;
        tail = NextObj(tail); // tail = start;
        start += size;
    }

    NextObj(tail) = nullptr;

	//对spanlist加锁
   list.mtx.lock();
   list.FrontPush(span);
    
  return span;
}

size_t CentralCache::FetchRangeObj(void*& start,
    void*& end,
    size_t batchNum,
    size_t size) {
    
	//先对spanlist加锁
  _spanLists[SizeClass::Index(size)].mtx.lock();
  Span* span = GetOneSpan(_spanLists[SizeClass::Index(size)], size);
  
  size_t actualNum = 1;
  
  void* _freeList = span->_freeList;
  start = _freeList;
  end = start;
  assert(_freeList);
  size_t i = 0;
  
  //将连续内存块切分
  while (i < batchNum - 1 && NextObj(end) != nullptr) {
    end = NextObj(end);
    ++i;
    ++actualNum;
  }
  span->_useCount += actualNum;
  

  span->_freeList = NextObj(end);

  NextObj(end) = nullptr;

  _spanLists[SizeClass::Index(size)].mtx.unlock();

  return actualNum;
}

void CentralCache::ReleaseLisToSpans(void* start, size_t size) {
    assert(start);
    size_t index = SizeClass::Index(size);

    _spanLists[index].mtx.lock();
   
    while (start) {

        Span* span = (Span*)PageCache::GetInstance()->MapObjectToSpan((PAGE_ID)start >> PAGE_SHIFT);
		//Span* span = (Span*)PageCache::GetInstance()->_pagemap.get((PAGE_ID)start >> PAGE_SHIFT);
        void* next = NextObj(start);      
		//切分的内存块加入到span的自由链表中
        NextObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount--;


		//如果usecount为零说名span没有被使用
		//可以释放到pagecache中
        if (span->_useCount == 0) {
            _spanLists[index].Erase(span);
            span->_freeList = nullptr;
            span->_next = nullptr;
            span->_pre = nullptr;


            


            _spanLists[index].mtx.unlock();

            PageCache::GetInstance()->mtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->mtx.unlock();                     
            _spanLists[index].mtx.lock();
        }

        start = next;
        
    }

   _spanLists[index].mtx.unlock();



}




CentralCache CentralCache::_sInst;